using System;
using System.Configuration;
using System.Data;
using System.Data.Entity;
using System.Data.Entity.Infrastructure;
using System.Linq;
using System.Web.Mvc;
using AutoMapper;
using Autofac;
using Autofac.Integration.Mvc;
using SapaFinance.Domain;
using SapaFinance.Domain.BusinessLogic;
using SapaFinance.Domain.EntityFramework;
using SapaFinance.Domain.Model;
using SapaFinance.Domain.Specifications;
using SapaFinance.GenericRepository;
using SapaFinance.GenericRepository.EntityFramework;
using SapaFinance.OOMap;
using SapaFinance.OOMap.Helpers;
using SapaFinance.Services;

namespace SapaFinance.UI
{
   
    public static class IOC
    {
        private static IContainer _container;
        public static readonly string ConnectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;

        public static IContainer Container
        {
            get { return _container; }
        }

        public static void Build()
        {
            var builder = new ContainerBuilder();
            builder.RegisterControllers(typeof (MvcApplication).Assembly);
            //infrastructure
            builder.Register(x => new DbContext(ConnectionString, new DbModelConfigure(ConnectionString).CompiledModel)).As<DbContext>();
            builder.RegisterType<EntityFrameworkUnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
            builder.Register(x => new SpecificationLocatorStub(_container)).As<ISpecificationLocator>();
            builder.Register(x => new EntityFrameworkUnitOfWorkConvertor()).As<IUnitOfWorkConvertor>();
            builder.Register(x => new AutoMapperConfiguration(DependencyResolver.Current).Engine).As<IMappingEngine>();
            //repositories
            builder.RegisterGeneric(typeof(GenericRepository<,>)).As(typeof(IGenericRepository<,>));
            //specifications
            builder.RegisterType<BudgetItemQueryableSpecification>().As<IBudgetItemSpecification>();
            builder.RegisterType<CurrencyQueryableSpecification>().As<ICurrencySpecification>();
            builder.RegisterType<UserQueryableSpecification>().As<IUserSpecification>();
            builder.RegisterType<RequestQueryableSpecification>().As<IRequestSpecification>();
            builder.RegisterType<CorporationQueryableSpecification>().As<ICorporationSpecification>();
            builder.RegisterType<AgentQueryableSpecification>().As<IAgentSpecification>();
            builder.RegisterType<AccountQueryableSpecification>().As<IAccountSpecification>();
            //converters
            builder.RegisterType<RequestToOrderDTOConvert>().As<RequestToOrderDTOConvert>();
            builder.RegisterType<BankToSelectListConvert>().As<BankToSelectListConvert>();
            builder.RegisterType<CurrencyToSelectListConvert>().As<CurrencyToSelectListConvert>();
            builder.RegisterType<PaymentTypeToSelectListConvert>().As<PaymentTypeToSelectListConvert>();
            builder.RegisterType<CorporationToSelectListConvert>().As<CorporationToSelectListConvert>();
            builder.RegisterType<BudgetItemToSelectListConvert>().As<BudgetItemToSelectListConvert>();
            builder.RegisterType<CFOToSelectListConvert>().As<CFOToSelectListConvert>();
            builder.RegisterType<AccountToSelectListConvert>().As<AccountToSelectListConvert>();
            builder.RegisterType<RequestToRequestDTOConvert>().As<RequestToRequestDTOConvert>();
            builder.RegisterType<OrderToOrderDTOConvert>().As<OrderToOrderDTOConvert>();
            builder.RegisterType<AccountToAccountDTOConvert>().As<AccountToAccountDTOConvert>();
            builder.RegisterType<CorporationToCorporationDTOConvert>().As<CorporationToCorporationDTOConvert>();
            builder.RegisterType<BankToBankDTOConvert>().As<BankToBankDTOConvert>();
            //services
            builder.RegisterType<AgentService>().As<IAgentService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<BankService>().As<IBankService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<BudgetItemService>().As<IBudgetItemService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<CurrencyService>().As<ICurrencyService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<AccountService>().As<IAccountService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<CorporationService>().As<ICorporationService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<PaymentTypeService>().As<IPaymentTypeService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope()
                .OnActivated(e => e.Instance
                                      .RegisterPayerStrategy(typeof (AgentNonCash).Name, e.Context.Resolve<PayerListAgentNonCash>())
                                      .RegisterPayerStrategy(typeof (NonCash).Name, e.Context.Resolve<PayerListNonCash>()));
            builder.RegisterType<CfoService>().As<ICfoService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<RequestService>().As<IRequestService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<OrderService>().As<IOrderService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            builder.RegisterType<UserService>().As<IUserService>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            //strategy
            builder.RegisterType<PayerListAgentNonCash>().As<PayerListAgentNonCash>();
            builder.RegisterType<PayerListNonCash>().As<PayerListNonCash>();
            //businessrules
            builder.RegisterType<IdenticalPayeeRule>().As<IdenticalPayeeRule>();
            builder.RegisterType<IdenticalPayerRule>().As<IdenticalPayerRule>();
            builder.RegisterType<CheckOrderSum>().As<CheckOrderSum>();
            //combine businessrules
            builder.Register(x => new CombineToOrderCompositeRule()).As<ICombineToOrderCompositeRule>()
                .OnActivated(e => e.Instance
                                      .AddRule(e.Context.Resolve<IdenticalPayeeRule>())
                                      .AddRule(e.Context.Resolve<IdenticalPayerRule>()));
            builder.Register(x => new CreateOrderCompositeRule()).As<ICreateOrderCompositeRule>()
                .OnActivated(e => e.Instance
                                      .AddRule(e.Context.Resolve<CheckOrderSum>()));
            //factory
            builder.RegisterType<EntityFactory>().As<IEntityFactory>().PropertiesAutowired(PropertyWiringFlags.AllowCircularDependencies).InstancePerLifetimeScope();
            _container = builder.Build();
            DependencyResolver.SetResolver(new AutofacDependencyResolver(_container));
        }

        public static void Dispose()
        {
            _container.Dispose();
        }

        //public static T Resolve<T>()
        //{
        //    if (_container == null)
        //        Build();
        //    return _container.Resolve<T>();
        //}
        //public static object Resolve(Type t)
        //{
        //    if (_container == null)
        //        Build();
        //    return _container.Resolve(t);
        //}
    }
}